package cuid.sc20.laboratory.interceptor;


//import cn.hutool.jwt.Claims;

import cuid.sc20.laboratory.utils.CookieUtils;
import cuid.sc20.laboratory.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.security.SignatureException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;


@Component
public class LoginInterceptor implements HandlerInterceptor {
    private Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);
    public static final String COOKIE_TOKEN_KEY = "authorization";
    private StringRedisTemplate redisTemplate;

    @Autowired
    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /*
            返回 true  代表放行请求   Cookie中有token
            返回 false 代表拦截请求
         */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //-- Cookie ：authorization = token     作为key从redis取值！
        //-- Redis  : token = token
        Cookie cookie = CookieUtils.getCookie(request, COOKIE_TOKEN_KEY);
        if (Objects.isNull(cookie)) {
            //-- 从来没有登陆过或者前端清除了Cookie
            //应当直接登录获取token
            return true;
//            throw new JwtException("Token不存在");
        }
        logger.info("1111111");
        String cookieToken = cookie.getValue();
        //-- 以cookie中的token为键，到redis中取值
        ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
        String redisToken = opsForValue.get(cookieToken);
        logger.info("cookie token:         " + cookieToken);
        logger.info("redis  token:         " + redisToken);
        //-- 如果redis中没有这个键，返回的是null
        if (Objects.isNull(redisToken)) {
            //-- redis key的过期时间是token的2倍  用来模拟长token  如果redis都过期了，就代表token彻底过期了
            throw new JwtException("Token已过期");
        }
        logger.info("222222");
        //-- 验证token有没有被篡改
        //--  我们没有在生成token时，添加过期时间，只是回避了过期的异常，还有  其它四种异常要考虑在内
        try {
            Claims claims = JwtUtils.parseHmacJWTWithOutExpTime(redisToken);
            //-- 如果没有产生异常，只能表示 token可以被解析
        } catch (Exception e) {
            throw new JwtException("Token解析失败");
        }
        logger.info("333333");
        //-- 处理过期时间  如果token本身没有过期，则直接放行，如果过期了，则续签
        Claims claims = JwtUtils.parseHmacJWT(redisToken);
        if (Objects.isNull(claims)) {
            logger.info("5555555");
            //-- token 过期了 但是redis 没有过期 ，触发续签
            logger.info("token 续签");
            //-- 续签就是重新生成一个
            Map<String, Object> map = new HashMap<>();
            map.put("name", "admin");
            map.put("role", "美少女战士");
            String newToken = JwtUtils.createHmacJWT(map, null);
            CookieUtils.setCookie(response, COOKIE_TOKEN_KEY, newToken, null);
            redisTemplate.delete(cookieToken);
            opsForValue.set(newToken, newToken, 2, TimeUnit.MINUTES);
        }
        logger.info("444444");
        //-- 直接放行的： token没有过期
        return true;
    }
}